﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Windows.Browser;
using System.Json;
using System.Linq;
using System.Xml;
using System.IO;

namespace Vertigo.SlideShow
{
    /// <summary>
    /// Picasa Data Provider for   Vertigo Slide.Show 2
    /// </summary>
    [ScriptableType]
    public class PicasaDataProvider : IDataProvider
    {
        #region Constants

        private string AlbumFeedsUrl = @"http://picasaweb.google.com/data/feed/api/user/{0}?alt=json-in-script&callback=album_callback";
        private string PicFeedsUrl = @"http://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}?alt=json-in-script&callback=pic_callback";
      

        #endregion

        #region Private Fields

        private int m_albumLevelCounter = 0;
        private int m_slideLevelCounter = 0;
        private Album[] Albums;
        private string[] AlbumIDs;
        private string[] AllowedAlbums;
        private bool AlbumFilterFlag;
        private string PicasaID;

        #endregion

        #region IDataProvider Members

        /// <summary>
        /// Occurs when [data finished loading].
        /// </summary>
        public event EventHandler DataFinishedLoading;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="PicasaDataProvider"/> class.
        /// </summary>
        /// <param name="initParams"></param>
        public PicasaDataProvider(Dictionary<string, Dictionary<string, string>> initParams)
        {
            PicasaID = initParams.ContainsKey("DataProvider") ?
                                    initParams["DataProvider"].ContainsKey("PicasaId") ?
                                            initParams["DataProvider"]["PicasaId"] :
                                            string.Empty : 
                                            string.Empty;

            string strAlbums = initParams.ContainsKey("DataProvider") ?
                                    initParams["DataProvider"].ContainsKey("Albums") ?
                                            initParams["DataProvider"]["Albums"] :
                                            string.Empty :
                                            string.Empty;

            string strDelimiter = initParams.ContainsKey("DataProvider") ?
                                    initParams["DataProvider"].ContainsKey("Delimiter") ?
                                            initParams["DataProvider"]["Delimiter"] :
                                            "^^" :
                                            "^^";
            if (!string.IsNullOrEmpty(strAlbums))
            {
                AllowedAlbums = strAlbums.Split(new string[] { strDelimiter }, StringSplitOptions.RemoveEmptyEntries);
                for (int i =0; i<AllowedAlbums.Length; i++)
                {
                    AllowedAlbums[i] = AllowedAlbums[i].Trim();
                }
                AlbumFilterFlag = true;
            }
            else
            {
                AllowedAlbums = null;
                AlbumFilterFlag = false;
            }

           
            if (string.IsNullOrEmpty(PicasaID))
            {
                throw new Exception("Error while retriving Picasa Data : Invalid Picasa ID ");
            }


            WriteJSToClentHtmlPage();


        }
        #endregion

        #region Call-Back Scriptable Methods

        [ScriptableMember]
        public void ParseAlbumData(string data)
        {
            JsonArray feedEntries = GetFeedEntries(data);
            string albumId = string.Empty;
            if (feedEntries != null & feedEntries.Count > 0)
            {
                this.Albums = new Album[feedEntries.Count];
                this.AlbumIDs = new string[feedEntries.Count];
                foreach (var entry in feedEntries)
                {
                    Albums[m_albumLevelCounter] = new Album();
                    JsonObject jAlbum = (JsonObject)JsonObject.Load(new StringReader(entry.ToString()));
                    var jAlbumTrimed = from b in jAlbum
                                       where b.Key == "title" || b.Key == "summary" || b.Key == "gphoto$id" || b.Key == "media$group"
                                       select b;
                    foreach (var jAlbumMember in jAlbumTrimed)
                    {
                        switch (jAlbumMember.Key)
                        {
                            case "title":
                                {
                                    Albums[m_albumLevelCounter].Title = jAlbumMember.Value["$t"]; 
                                    break;
                                }
                            case "summary":
                                {
                                    Albums[m_albumLevelCounter].Description = jAlbumMember.Value["$t"]; 
                                    break;
                                }
                            case "gphoto$id":
                                {
                                    albumId = jAlbumMember.Value["$t"];
                                    break;
                                }
                            case "media$group":
                                {
                                    JsonObject mediaGroup = (JsonObject)JsonObject.Load(new StringReader(jAlbumMember.Value.ToString()));
                                    Albums[m_albumLevelCounter].Thumbnail = new Uri(GetValueFromMediaGroup(mediaGroup, "media$thumbnail", "url"));
                                    break;
                                }
                        }
                      
                    }
                    AlbumIDs[m_albumLevelCounter] = albumId;
                    if (AlbumFilterFlag == true)
                    {
                        if (Array.IndexOf(AllowedAlbums, Albums[m_albumLevelCounter].Title) > -1)
                        {
                            HtmlPage.Window.Invoke("injectScript", string.Format(PicFeedsUrl, PicasaID, albumId));
                            m_albumLevelCounter += 1;
                        }
                    }
                    else
                    {
                        HtmlPage.Window.Invoke("injectScript", string.Format(PicFeedsUrl, PicasaID, albumId));
                        m_albumLevelCounter += 1;
                    }
                   
                   
                }

            }
            else
            {
                throw new Exception("Invalid data from feed");
            }
            if (m_albumLevelCounter == 0)
            {
                MessageBox.Show("Oops.. no matching albums found.");
            }
           
        }

        [ScriptableMember]
        public void ParsePicData(string data)
        {
            string currentAlbumID;
            JsonArray feedEntries = GetFeedEntries(data, out currentAlbumID);
            Slide[] allSlidesPerAlbum;
            
            if (feedEntries != null && feedEntries.Count > 0)
            {
                allSlidesPerAlbum = new Slide[feedEntries.Count];
                int indexVar = 0;
                foreach (var entry in feedEntries)
                {
                    Slide oneSlide = new Slide();
                    JsonObject jPhoto = (JsonObject)JsonObject.Load(new StringReader(entry.ToString()));
                    var jTrimedPhoto = from b in jPhoto
                                       where b.Key == "title" || b.Key == "summary" || b.Key == "media$group" 
                                       select b; 
                    foreach (var jPhotoMember in jTrimedPhoto)
                    {

                        if (jPhotoMember.Key == "title")
                        {
                            oneSlide.Title = jPhotoMember.Value["$t"]; continue;
                        }
                        if (jPhotoMember.Key == "summary")
                        {
                            oneSlide.Description = jPhotoMember.Value["$t"]; continue;
                        }
                        if (jPhotoMember.Key == "media$group")
                        {
                            JsonObject mediaGroup = (JsonObject)JsonObject.Load(new StringReader(jPhotoMember.Value.ToString()));

                            oneSlide.Thumbnail = new Uri(GetValueFromMediaGroup(mediaGroup, "media$thumbnail", "url"));
                            oneSlide.Source = new Uri(GetValueFromMediaGroup(mediaGroup, "media$content", "url"));
                            continue;
                        }
                      
                    }
                    oneSlide.Transition = GetRandomTransition();
                    allSlidesPerAlbum[indexVar] = oneSlide;
                    indexVar += 1;
                    

                }

            }
            else
            {
                allSlidesPerAlbum = new Slide[0];
            }
            int temp = 0;
            for (temp = 0; temp < Albums.Length; temp++)
            {
                if (AlbumIDs[temp] == currentAlbumID) break;
            }
            if (temp < Albums.Length)
            {
                Albums[temp].Slides = allSlidesPerAlbum;
                m_slideLevelCounter += 1;
            }
            if (m_albumLevelCounter == m_slideLevelCounter)
            {
                Data.Albums = (from album in Albums
                               where album != null && album.Slides != null && album.Slides.Length > 0
                               select album).ToArray<Album>();
                Data.StartAlbumIndex = 0;
                DataFinishedLoading(this, EventArgs.Empty);
            }
            
            
        }

       
        #endregion
           
        #region Private Supporting Methods

        [ScriptableMember]
        private void WriteJSToClentHtmlPage()
        {
            try
            {
                HtmlPage.RegisterScriptableObject("PicasaDataProvider", this);

                HtmlDocument doc = HtmlPage.Document;
                ScriptObjectCollection elementColl = doc.GetElementsByTagName("head");
                HtmlElement head = (HtmlElement)elementColl[0];


                //adding ref to http://json.org/json2.js
                HtmlElement jsonScriptElement = doc.CreateElement("script");
                jsonScriptElement.SetAttribute("type", "text/javascript");
                jsonScriptElement.Id = "json_org_json2_js";
                jsonScriptElement.SetAttribute("src", "http://json.org/json2.js");
                head.AppendChild(jsonScriptElement);

                //adding JS for JSON call
                string jsText;
                jsText = "function injectScript(url) { var head = document.getElementsByTagName('head')[0];   var script = document.createElement('script');  script.type = 'text/javascript';   script.src = url;   head.appendChild(script); }; ";
                jsText += "function album_callback(obj) {var m_silverlight = document.getElementById('SLControl'); if (m_silverlight) {m_silverlight.Content.PicasaDataProvider.ParseAlbumData(JSON.stringify(obj));  }  };";
                jsText += "function pic_callback(obj) {var m_silverlight = document.getElementById('SLControl'); if (m_silverlight) {m_silverlight.Content.PicasaDataProvider.ParsePicData(JSON.stringify(obj));  }  };";

                HtmlElement scriptElement = doc.CreateElement("script");
                scriptElement.SetAttribute("type", "text/javascript");
                scriptElement.Id = "pb_JsonScript";
                scriptElement.SetProperty("text", jsText);
                head.AppendChild(scriptElement);
                if (HtmlPage.Document.IsReady)
                {
                    HtmlPage.Window.Invoke("injectScript", string.Format(AlbumFeedsUrl, PicasaID));
                }
                else  // hack for firefox
                {
                    HtmlPage.Document.DocumentReady += new EventHandler(Document_DocumentReady);
                }
                
            }
            catch (Exception ex) 
            {
                
                MessageBox.Show("Error: " + ex.Message);
            }
        }

        void Document_DocumentReady(object sender, EventArgs e)
        {
            try
            {
                HtmlPage.Window.Invoke("injectScript", string.Format(AlbumFeedsUrl, PicasaID));
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error : " + ex.Message);
            }
        }


        private JsonArray GetFeedEntries(string jsonString, out string  gphotoId)
        {
            gphotoId = string.Empty;
            try
            {
                JsonObject jData = (JsonObject)JsonObject.Load(new StringReader(jsonString));
                var feedElement_t = (from feed in jData
                                     where feed.Key == "feed"
                                     select feed.Value).First();
                JsonObject feedElement = (JsonObject)JsonObject.Load(new StringReader(feedElement_t.ToString()));

                var tt = (from feedEntry in feedElement
                          where feedEntry.Key == "gphoto$id"
                          select feedEntry.Value).First();
                gphotoId = tt["$t"].ToString();
                gphotoId = gphotoId.Substring(1, gphotoId.Length - 2);
                var feedEntries_t = (from feedEntry in feedElement
                                     where feedEntry.Key == "entry"
                                     select feedEntry.Value).First();
                return feedEntries_t as JsonArray;

            }
            catch
            {
                
                return null;
            }
            
 
        }

        private JsonArray GetFeedEntries(string jsonString)
        {

            try
            {
                JsonObject jData = (JsonObject)JsonObject.Load(new StringReader(jsonString));
                var feedElement_t = (from feed in jData
                                     where feed.Key == "feed"
                                     select feed.Value).First();
                JsonObject feedElement = (JsonObject)JsonObject.Load(new StringReader(feedElement_t.ToString()));

                var feedEntries_t = (from feedEntry in feedElement
                                     where feedEntry.Key == "entry"
                                     select feedEntry.Value).First();
                return feedEntries_t as JsonArray;

            }
            catch (Exception ex)
            {

                 throw new Exception("Error in PicasaDataProvider.GetFeedEntries()", ex);
            }


        }
           
            
        

        private string GetValueFromMediaGroup(JsonObject mediaGroup,  string category, string subCategory)
        {
            var mediaCategory_t = (from p in mediaGroup
                                  where p.Key == category
                                  select p.Value).First();
            JsonArray mediaCategory = (JsonArray)mediaCategory_t;
            JsonObject jContent = ((JsonObject)JsonObject.Load(new StringReader(mediaCategory[0].ToString())));
            return jContent[subCategory];
        }

        #region For Generating Random Transactions
        private static Random R = new Random();
        private string GetRandomTransition()
        {
            string[] transactions = new string[] {"CircleInTransition", "CircleOutTransition",  "CrossFadeTransition",  
                                                    "SlideDownTransition", "SlideLeftTransition", "SlideRightTransition",  
                                                    "SlideUpTransition", "TranslateDownTransition", "TranslateLeftTransition", 
                                                    "TranslateRightTransition","TranslateUpTransition"  };

            return transactions[R.Next(0, transactions.Length)];
        }
        #endregion

        #endregion

    }

   
}
